// 用一个全局变量来存储当前激活的effect函数
let activeEffect;
// effect
const effectStack = [];
export function effect(fn, options = {}) {
  // 创建一个effect函数
  const effectFn = () => {
    cleanup(effectFn);

    // 将当前effect函数设置为激活状态
    activeEffect = effectFn;

    // 当前激活的effect函数,将其压入栈中
    effectStack.push(activeEffect);

    // 执行用户传入的fn函数
    const res = fn();
    // 执行完毕后,将当前effect函数从激活状态中移除
    effectStack.pop();

    // 将当前的激活effect函数设置为栈顶的effect函数
    // 这样可以确保在嵌套的effect函数中,能够正确地恢复到上一个激活的effect函数
    activeEffect = effectStack[effectStack.length - 1];
    return res;
  };
  // 将options挂载到effectFn上
  effectFn.options = options;
  // activeEffect.deps 用来存储所有与该副作用函数相关的依赖集合
  effectFn.deps = [];
  //   只有非lazy选项时,才会立即执行副作用函数
  if (!options.lazy) {
    effectFn();
  }
  // 执行副作用函数
  return effectFn;
}

// 清理函数
export function cleanup(effectFn) {
  // 如果effectFn.deps存在,则遍历deps数组
  if (effectFn.deps.length) {
    // 遍历deps数组,清除所有与该副作用函数相关的依赖集合
    effectFn.deps.forEach((dep) => {
      dep.delete(effectFn);
    });
    // 清空effectFn.deps数组
    effectFn.deps.length = 0;
  }
}

// 定义一个任务队列
const jobQueue = new Set();
// 定义一个函数来将任务添加到任务队列中
const p = Promise.resolve();
// 定义一个标志位,用来判断是否正在执行任务队列
let isFlushing = false;
// 定义一个函数来清理任务队列
export function flushJob() {
  // 如果正在执行任务队列,则直接返回
  if (isFlushing) return;
  // 设置标志位为true,表示正在执行任务队列
  isFlushing = true;

  // 遍历任务队列中的所有任务
  p.then(() => {
    jobQueue.forEach((job) => {
      // 执行任务
      job();
    });
  }).finally(() => {
    // 重置标志位为false,表示任务队列执行完毕
    isFlushing = false;
  });

  // 清空任务队列
  jobQueue.clear();
}

// 使用WeakMap可以自动清理不再使用的依赖关系,避免内存泄漏
const bucket = new WeakMap(); // 使用WeakMap来存储响应式数据的依赖关系

/**
 * 响应函数
 * @param {*} target
 * @param {*} key
 * @returns
 */
export function trigger(target, key) {
  const depsMap = bucket.get(target);
  if (!depsMap) return;
  const effects = depsMap.get(key);
  const effectsToRun = new Set(); //
  if (effects) {
    effects.forEach((effectFn) => {
      //  如果trigger触发执行的副作用函数与当前正在执行的副作用函数相同,则不触发执行;避免无线递归循环
      // 这样可以避免在同一个effect函数中触发自身的副作用
      if (effectFn !== activeEffect) {
        effectsToRun.add(effectFn);
      }
    });
  }
  effectsToRun.forEach((effectFn) => {
    if (effectFn.options.scheduler) {
      // 如果effectFn有scheduler选项,则调用scheduler
      effectFn.options.scheduler(effectFn);
    } else {
      // 否则直接执行effectFn
      effectFn();
    }
  });
}

// 追踪函数
export function track(target, key) {
  // 如果没有activeEffect,则不进行追踪
  if (!activeEffect) return;
  // 获取target在bucket中的depsMap
  let depsMap = bucket.get(target);
  // 如果不存在,则创建一个新的depsMap
  if (!depsMap) {
    depsMap = new Map();
    bucket.set(target, depsMap);
  }
  // 获取key在depsMap中的effect集合
  let effects = depsMap.get(key);
  // 如果不存在,则创建一个新的effect集合
  if (!effects) {
    effects = new Set();
    depsMap.set(key, effects);
  }
  // 将当前的activeEffect添加到effects集合中
  effects.add(activeEffect);
  // 将当前的activeEffect添加到activeEffect.deps数组中
  activeEffect.deps.push(effects);
}

// 定义一个全局的桶,用来存储所有的响应式数据
export function createProxy(target) {
  // 返回一个代理对象
  return new Proxy(target, {
    get(target, key) {
      // 当读取属性时,触发track函数
      track(target, key);
      return Reflect.get(target, key);
    },
    set(target, key, value) {
      // 当设置属性时,更新数据并触发trigger函数
      const oldValue = target[key];
      const result = Reflect.set(target, key, value);
      if (oldValue !== value) {
        trigger(target, key);
      }
      return result;
    },
  });
}
